#pragma once
#include <list>

class CFileReader : public IAsyncReader
{
    CFileReader(const CFileReader&);
    CFileReader& operator=(const CFileReader&);
    
public:

    CFileReader();
    virtual ~CFileReader();
    
    HRESULT Open(const wchar_t*);
    HRESULT Close();
    bool IsOpen() const;
    
    HRESULT STDMETHODCALLTYPE QueryInterface(const IID&, void**);
    ULONG STDMETHODCALLTYPE AddRef();
    ULONG STDMETHODCALLTYPE Release();

    //IAsyncReader
    
    HRESULT STDMETHODCALLTYPE RequestAllocator( 
        IMemAllocator*,
        ALLOCATOR_PROPERTIES*,
        IMemAllocator**);
    
    HRESULT STDMETHODCALLTYPE Request( 
        IMediaSample*,
        DWORD_PTR);
    
    HRESULT STDMETHODCALLTYPE WaitForNext( 
        DWORD,
        IMediaSample**,
        DWORD_PTR*);
    
    HRESULT STDMETHODCALLTYPE SyncReadAligned( 
        IMediaSample*);
    
    HRESULT STDMETHODCALLTYPE SyncRead( 
        LONGLONG,
        LONG,
        BYTE*);
    
    HRESULT STDMETHODCALLTYPE Length( 
        LONGLONG*,
        LONGLONG*);
    
    HRESULT STDMETHODCALLTYPE BeginFlush();
    HRESULT STDMETHODCALLTYPE EndFlush();
    
private:

    HANDLE m_hFile;
    ALLOCATOR_PROPERTIES m_props;
    LONGLONG m_length;
    bool m_bFlush;
    
    class ReadInfo
    {
        ReadInfo& operator=(const ReadInfo&);

    public:

        IMediaSample* const m_pSample;
        const DWORD_PTR m_user;
        
        ReadInfo() : m_pSample(0), m_user(0)
        {
        }
        
        ReadInfo(IMediaSample* p, DWORD_PTR u) :
            m_pSample(p),
            m_user(u)
        {
        }
        
        ReadInfo(const ReadInfo& rhs) :
            m_pSample(rhs.m_pSample),
            m_user(rhs.m_user)
        {
        }

    };
    
    typedef std::list<ReadInfo> read_queue_t;    
    read_queue_t m_read_queue;
    
    HRESULT SetPosition(LONGLONG) const;

};
